双周复盘:2026-07-03 至 2026-07-17
> 记录人:Dano Day > 项目:Daedalus > 时间范围:2026-07-03 至 2026-07-17
一、本周期核心结论
本周期交付了 6 个已合并 PR,覆盖 Crate、Archetype、Repository、Dictionary 四个模块,同时推进了本地工程质量基建(lefthook / oxlint)。整体来看,交付密度高、模块耦合深,但也暴露出一些可沉淀为规范的问题:
- 复杂表单的状态同步需要在设计阶段就明确单一数据源;
- 并行需求修改同一 schema 时,migration 管理容易冲突;
- 性能需求需要可编程的自动化基准,而非依赖手工验收;
- 跨层 Job 上下文需要稳定的序列化契约;
- UI 组件规范需要在编码前主动检查,而非在 review 中被动修复。
二、按需求复盘
1. COD-171:Crate 关联路径 —— 状态同步与交互设计
背景
COD-171 经历了 7 月 14 日首次实现 → 当天 fix → 当天 revert → 7 月 15 日重写 → 7 月 16 日合并的曲折过程。问题根源在于第一版采用了「路径草稿输入区 + 添加按钮 + 只读列表」的双轨交互。
问题
- 状态双轨维护:
pathDraft/pathTypeDraft本地 state 与 React Hook Form 的paths数组并行存在,提交时容易出现 stale closure,导致最新输入未进入 payload。 - 静默失败:空值和重复值被静默忽略,用户无法判断输入是否生效。
- 新增与编辑两套交互:已添加的路径不能直接修改,体验割裂。
最终方案
- 拆出
CratePathsField领域组件; - 所有路径行直接作为 React Hook Form field array 元素;
- 点击「添加路径」立即新增一行并聚焦,不再有草稿状态;
- 共享 Zod Schema 在前端和后端统一校验,错误定位到行。
复盘点
- 复杂表单应避免本地 state 与表单 state 双轨维护。任何需要提交的字段都应尽早纳入统一表单模型,临时草稿只在极短交互(如一次性搜索)中使用。
- 表单校验不应静默失败。空值、重复值、非法格式都应显式提示并阻止提交。
- 新增与编辑尽量使用同一种交互模式。减少用户认知负担,也减少代码分支。
- 领域组件拆分要早做。如果第一天就把路径编辑拆成
CratePathsField,而不是内嵌在CrateDialog中,会更容易测试和迭代。
2. COD-173 / COD-174:Crate Repository 归属与筛选 —— Migration 与 N+1
背景
该 PR 同时包含 Repository 归属、列表筛选、批量 enrichment 与 UI 组件规范修复。
问题
- Migration 冲突:分支中原先生成了未登记的
0010_melted_nocturne.sql,与 develop 已有 migration 冲突,最终需要删除并重新生成0011。 - 解绑语义不清晰:最初未区分「未提供字段(undefined)」与「明确解绑(null)」,导致解绑失败。
- 列表 N+1:最初在 Service 层逐 ID 查询
github_projects。 - 原生 UI 控件:新增搜索
input和 Repositoryselect使用了原生 HTML 元素,不符合项目 UI 规范, review 中被迫返工。
最终方案
- 删除冲突 migration,基于 develop 最新 snapshot 生成
0011; - 明确定义:
undefined= 不更新,string= 绑定,null= 解绑; - 在
github-projects-dao增加getByIds(ids)批量查询; - 将原生控件替换为
@/components/ui/input与@/components/ui/select。
复盘点
- 多需求并行改 schema 时,应在 develop 合并后立刻生成 migration。如果两个分支都生成
0010,必然冲突。建议在基线合并后的第一时间跑db:generate,并登记 journal。 - 外键关联的「解绑」语义应在 PRD 阶段就明确。
null、undefined、空字符串的语义差异虽小,但会显著影响 DAO/Service 实现与前端表单处理。 - 列表 enrichment 应在设计阶段就规划批量查询。Service 层拿到列表后,第一反应应是收集 ID 并批量查询,而不是循环逐条查。
- 编码前先检查
@/components/ui是否已有对应组件。CLAUDE.md 与项目规范都明确禁止在页面中重复写原生select/button/input,但仍容易顺手写出。建议在打开页面文件前先扫一眼 UI 组件目录。
3. COD-220:大型仓库文件树虚拟化 —— 性能验证的自动化缺口
背景
COD-220 将递归全量文件树改造为虚拟化渲染,解决了 500+ 节点仓库的滚动卡顿问题。
问题
- 性能验收依赖手工:执行计划中明确写「待真实大型仓库手工验收」,并记录为「待补自动化的技术债务」。
- Storybook 缺失:项目中没有可运行的 Storybook 工具链,无法为大仓库文件树建立独立、可重复的基准场景。
最终方案
- 使用
@tanstack/react-virtual限制实际挂载 DOM 行数; - 用纯函数处理展开状态与扁平化,便于单元测试;
- 通过固定行高、稳定 key、overscan 控制减少滚动跳动。
复盘点
- 性能需求应配套可编程的测试夹具。即使无法完全模拟真实 GitHub 仓库,也应构造确定性的 600+ 节点树夹具,并断言挂载节点数显著小于总节点数。
- 大组件需要独立的性能/交互基准环境。当前
apps/app缺少 Storybook,导致 COD-220 不得不把性能基准推迟。建议把 Storybook 基础设施作为独立需求提前补齐。 - 虚拟化组件的验收标准应能量化。例如:「视口内 + overscan 外不挂载 DOM」、「滚动 60fps」、「展开/折叠响应 < 100ms」。模糊的「流畅」容易在 review 中产生分歧。
4. COD-89 / COD-176:Archetype Conformance —— 跨层上下文的契约
背景
该需求将 Archetype Condition 转换为可执行检查项,并通过 Job 队列执行 conformance 扫描。涉及 crate-conformance-service、scan-orchestrator-service、pending Job 上下文恢复、Crate 详情页 Tab 重组。
问题
- 临时上下文序列化:Conformance 需要把普通表字段无法表达的临时
RuleContext和targetFiles保存到context_snapshotJSONB,再在 worker claim 时恢复。 - Job 队列分支bug:已有 Job 在上下文构建失败时应 update 而非重复 insert。
- 范围较大:同时改动 Service、Job、页面、Tab 组件,PR 仍在反复 In Review。
最终方案
- 复用现有
enqueueScan/executeScan流程; - 将临时规则与文件范围序列化到
context_snapshot; - 新增
TabsUI 组件重组 Crate 详情页; - worker 恢复上下文后调用现有扫描逻辑。
复盘点
- 跨层 Job 应尽早定义稳定的 context payload schema。临时 JSONB 字段虽然灵活,但序列化/反序列化逻辑分散在 Service 与 orchestrator 中,容易在接口变更时遗漏。建议抽离一个共享 schema,并在 worker 恢复时做严格校验。
- 队列状态机需要单元测试覆盖分支。"上下文构建失败时 update 而非 insert" 这类分支bug 说明 Job 生命周期测试不足。
- 大需求应拆分为可独立合并的子 PR。例如:先合 "Tabs 组件",再合 "Conformance Service 入队",最后合 "worker 上下文恢复"。当前单 PR 改动面过大,review 和回滚成本都高。
5. Dictionary 增强(COD-193 / 195 / 196 / 198)—— 范围合并与测试覆盖
背景
四个 Dictionary 相关需求合并为一个 PR #27 交付,包含 noun/verb 词条、标准写法、别名、反向引用。
问题
- PR 范围大:四个子需求共用一个 PR,文件改动多,review 周期长。
- 部分需求状态仍显示 In Review:Linear 上 COD-195/196/198 仍标记为 In Review,说明验收或收尾未完全结束。
复盘点
- 一个 PR 最好只承载一个可独立验收的需求。即使业务上相关,也应尽量拆分为独立分支,分别合并,降低 review 负担和回滚风险。
- 需求状态应与代码状态同步。PR 合并后应及时将 Linear issue 标记为 Done,避免信息不同步。
6. 工程质量基建 —— lefthook / oxlint
背景
当前分支 chore/add-lefthook 正在添加本地 pre-commit 钩子,并新增 prefer-cn oxlint 规则。
复盘点
- 本地 pre-commit 应与 CI 同源。避免「本机绿、CI 红」的关键不是增加更多检查,而是让本地命令与 CI 使用同一套脚本。
- 新增 lint 规则应评估存量违规。
prefer-cn这类规则如果存在大量存量违规,会导致所有提交都被阻断。建议先运行规则统计违规数量,必要时先 autofix 再启用规则。
三、通用教训
1. 设计文档应在编码前完成并沉淀
本周期多数需求都有 docs/COD-xxx/plan.md 或 docs/specs/*.md,但部分设计是在实现中逐步清晰的(如 COD-171 的可编辑路径行)。建议在分支创建前先完成设计文档,减少返工。
2. 私有/设计文档的 git 管理
7 月 3 日有多次 chore: untrack private docs 提交,说明设计文档曾误加入 git。建议:
- 创建
.md文件前先确认是否应被跟踪; - 统一使用
docs/private/或.claude/等明确目录,并在.gitignore中维护。
3. 表单与复杂状态优先使用单一数据源
COD-171 的 stale closure 问题是典型教训。凡是最终要提交的数据,都应直接放在 React Hook Form / Zod 模型中,避免中间草稿 state。
4. 数据库 migration 需要协调机制
当多个需求同时改 schema 时,应在每日同步中确认谁先合入 develop 并生成 migration,其他需求基于最新 snapshot 重新生成。
5. 性能需求需要量化指标和自动化基准
"流畅"、"不卡" 是主观描述。虚拟化、列表、大量 DOM 等性能敏感场景应配套:
- 可构造的测试夹具;
- 明确的性能指标(如挂载节点数、帧率、响应时间);
- 自动化断言,至少覆盖回归。
四、行动项
| 行动项 | 负责人 | 优先级 | 备注 |
|---|---|---|---|
| 制定「多分支改 schema 时 migration 协调」规范 | Dano / 团队 | 高 | 明确谁负责生成 snapshot、如何 rebase |
| 补齐 Storybook 基础设施 | 团队 | 中 | 为大组件提供独立基准环境 |
| 为 COD-220 建立可重复的虚拟化回归测试 | Dano | 中 | 构造 600+ 节点夹具,断言挂载节点数 |
| 定义 Job 上下文序列化的共享 schema | Dano | 高 | 防止 COD-89/176 这类跨层隐式契约 |
将 prefer-cn 规则存量问题清理后启用 | Dano | 中 | 避免 pre-commit 大规模阻断 |
| 建立「UI 组件先行检查」清单 | 团队 | 低 | 在 CLAUDE.md 或 PR 模板中强调 |
| 拆分未来大需求为独立子 PR | Dano | 高 | 如 Conformance 可拆为 Tabs / Service / Worker 三个 PR |
五、参考文档
- 本周期工作总结
docs/COD-171/plan.md— Crate 关联路径实现计划docs/specs/2026-07-15-crate-linked-path-editing-design.md— 可编辑路径行设计docs/specs/2026-07-15-crate-repository-fixes-design.md— Repository ownership 修复设计docs/specs/2026-07-16-crate-detail-tabs-conformance-job-navigation-design.md— Conformance Job 跳转设计docs/other/pr-crate-linked-paths.md— COD-171 PR 说明